library("tidyverse")
library("data.table")
library("rtracklayer")
library("ggrastr")
library("DESeq2")
library("ggpubr")
library("wigglescout")
library("eulerr")
library("ggplot2")

# export 
result_folder = "../results/wigglescout/"

bws <- list.files("../data/CutNTag_ChIP-Seq/bw/",
                  full.names = TRUE)
# diff signal function
bw_granges_diff_analysis <- function(granges_c1,
                                     granges_c2,
                                     label_c1,
                                     label_c2,
                                     estimate_size_factors = FALSE,
                                     as_granges = FALSE) {
  # Bind first, get numbers after
  names_values <- NULL
  fields <- names(mcols(granges_c1))
  
  if ("name" %in% fields) {
    names_values <- mcols(granges_c1)[["name"]]
    granges_c1 <- granges_c1[, fields[fields != "name"]]
  }
  
  fields <- names(mcols(granges_c2))
  if ("name" %in% fields) {
    granges_c2 <- granges_c2[, fields[fields != "name"]]
  }
  
  cts_df <- cbind(data.frame(granges_c1), mcols(granges_c2))
  
  if (!is.null(names_values)) {
    rownames(cts_df) <- names_values
  }
  
  # Needs to drop non-complete cases and match rows
  complete <- complete.cases(cts_df)
  cts_df <- cts_df[complete, ]
  
  values_df <- cts_df[, 6:ncol(cts_df)] %>% dplyr::select(where(is.numeric))
  cts <- get_nreads_columns(values_df)
  
  condition_labels <- c(rep(label_c1, length(mcols(granges_c1))), rep(label_c2, length(mcols(granges_c2))))
  
  
  coldata <- data.frame(colnames(cts), condition = as.factor(condition_labels))
  print(coldata)
  
  dds <- DESeq2::DESeqDataSetFromMatrix(
    countData = cts,
    colData = coldata,
    design = ~ condition,
    rowRanges = granges_c1[complete, ]
  )
  
  
  if (estimate_size_factors == TRUE) {
    dds <- DESeq2::estimateSizeFactors(dds)
  }
  else {
    # Since files are scaled, we do not want to estimate size factors
    sizeFactors(dds) <- c(rep(1, ncol(cts)))
  }
  
  dds <- DESeq2::estimateDispersions(dds)
  dds <- DESeq2::nbinomWaldTest(dds)
  
  if (as_granges) {
    result <- DESeq2::results(dds, format = "GRanges", alpha = 0.01)
    if (!is.null(names_values)) {
      result$name <- names_values[complete]
    }
    
  }
  else {
    # result <- results(dds, format="DataFrame")
    result <- dds
  }
  
  result
}

get_nreads_columns <- function(df, length_factor = 100) {
  # Convert mean coverages to round integer read numbers
  cts <- as.matrix(df)
  cts <- as.matrix(cts[complete.cases(cts), ])
  cts <- round(cts * length_factor)
  cts
}
ctcf.and.G4.pro <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_with_promoters.sorted-CTCF_G4.bed")
ctcf.not.G4.pro <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_with_promoters.sorted-CTCFonly.bed")
ctcf.and.G4.npr <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_without_promoters.sorted-CTCF_G4.bed")
ctcf.not.G4.npr <- import("../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories_without_promoters.sorted-CTCFonly.bed")

ctcf.and.G4.pro$class <- "CTCF_and_G4"
ctcf.not.G4.pro$class <- "CTCF_not_G4"
ctcf.and.G4.npr$class <- "CTCF_and_G4"
ctcf.not.G4.npr$class <- "CTCF_not_G4"
ctcf.and.G4.pro$pro <- "Pro"
ctcf.not.G4.pro$pro <- "Pro"
ctcf.and.G4.npr$pro <- "noPro"
ctcf.not.G4.npr$pro <- "noPro"

ctcf.and.G4 <- c(ctcf.and.G4.pro,ctcf.and.G4.npr)
ctcf.not.G4 <- c(ctcf.not.G4.pro,ctcf.not.G4.npr)
ctcf <- c(ctcf.and.G4,ctcf.not.G4)
ctcf <- sortSeqlevels(ctcf)
ctcf <- sort(ctcf)
names(ctcf) <- paste0(ctcf$class," ",ctcf$pro)
peaks_bed <- "../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories.bed"
export.bed(ctcf, "../data/CutNTag_ChIP-Seq/bed/Wulfridge_CTCF_in_6_categories.bed")
# Wulfridge CTCF ChIP-Seq mocks
mocks_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958387_GSM7116277_E14_Mock_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
          "../data/CutNTag_ChIP-Seq/bw/SRR23958386_GSM7116278_E14_Mock_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

# PDS
# Wulfridge CTCF ChIP-Seq
pds_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958385_GSM7116279_E14_PDS_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958384_GSM7116280_E14_PDS_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

pdc_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/SRR23958383_GSM7116281_E14_PhenDC3_CTCF_Rep1_Mus_musculus_ChIP-Seq.CPMnorm.bw",
                "../data/CutNTag_ChIP-Seq/bw/SRR23958382_GSM7116282_E14_PhenDC3_CTCF_Rep2_Mus_musculus_ChIP-Seq.CPMnorm.bw")

G4_bigwigs = c("../data/CutNTag_ChIP-Seq/bw/G4_CnT_NT_batch3_R1.unique.bw")

cov.mocks <- bw_loci(mocks_bigwigs,peaks_bed,labels=c("mock_1","mock_2"))
cov.pds <- bw_loci(pds_bigwigs,peaks_bed,labels=c("PDS_1","PDS_2"))
cov.pdc <- bw_loci(pdc_bigwigs,peaks_bed,labels=c("PhenDC3_1","PhenDC3_2"))
cov.G4 <- bw_loci(G4_bigwigs,peaks_bed,labels=c("G4_NT"))
results <- data.frame(
  as.data.frame(cov.mocks),
  as.data.frame(cov.pds)[6:7],
  as.data.frame(cov.pdc)[6:7],
  as.data.frame(cov.G4)[6],
  raw.lfc.pds_1 = log2(cov.pds$PDS_1/cov.mocks$mock_1),
  raw.lfc.pds_2 = log2(cov.pds$PDS_2/cov.mocks$mock_2),
  raw.lfc.pdc_1 = log2(cov.pds$PDS_1/cov.mocks$mock_1),
  raw.lfc.pdc_2 = log2(cov.pdc$PhenDC3_2/cov.mocks$mock_2),
  raw.lfc.pds = log2(rowMeans(as.data.frame(cov.pds)[6:7])/rowMeans(as.data.frame(cov.mocks)[6:7])),
  raw.lfc.pdc = log2(rowMeans(as.data.frame(cov.pdc)[6:7])/rowMeans(as.data.frame(cov.mocks)[6:7])),
  mean.mock = rowMeans(as.data.frame(cov.mocks)[6:7]),
  mean.pds = rowMeans(as.data.frame(cov.pds)[6:7]),
  mean.pdc = rowMeans(as.data.frame(cov.pdc)[6:7])
  )

cov.mocks$name <- NULL
cov.pds$name <- NULL
cov.pdc$name <- NULL

de_pds <- bw_granges_diff_analysis(cov.mocks,cov.pds,"Mock","PDS")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pds = DESeq2::lfcShrink(de_pds, coef = "condition_PDS_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
de_pdc <- bw_granges_diff_analysis(cov.mocks,cov.pdc,"Mock","PhenDC3")
converting counts to integer mode
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
lfc_pdc = DESeq2::lfcShrink(de_pdc, coef = "condition_PhenDC3_vs_Mock", type = "apeglm")
using 'apeglm' for LFC shrinkage. If used in published research, please cite:
    Zhu, A., Ibrahim, J.G., Love, M.I. (2018) Heavy-tailed prior distributions for
    sequence count data: removing the noise and preserving large differences.
    Bioinformatics. https://doi.org/10.1093/bioinformatics/bty895
results$deseq.lfc.pds <- results(de_pds)$log2FoldChange
results$deseq.lfcs.pds <- lfc_pds$log2FoldChange
results$deseq.padj.pds <- lfc_pds$padj
results$deseq.mean.pds <- log2(lfc_pds$baseMean)
results$deseq.sig.pds <- lfc_pds$pvalue < 0.05

results$deseq.lfc.pdc <- results(de_pdc)$log2FoldChange
results$deseq.lfcs.pdc <- lfc_pdc$log2FoldChange
results$deseq.padj.pdc <- lfc_pdc$padj
results$deseq.mean.pdc <- log2(lfc_pdc$baseMean)
results$deseq.sig.pdc <- lfc_pdc$pvalue < 0.05

results$class <- gsub(" .+","",results$name)
results$pro <- gsub(".+ ","",results$name)
results$class <- factor(results$class,levels=c("CTCF_and_G4","CTCF_not_G4"))

results$log2.mock <- log2(results$mean.mock)
results$log2.pds <- log2(results$mean.pds)
results$log2.pdc <- log2(results$mean.pdc)
results$log2.G4 <- log2(results$G4_NT)

results$deseq.sigup.pds <- results$deseq.sig.pds & results$deseq.lfc.pds > 0
results$deseq.sigup.pdc <- results$deseq.sig.pdc & results$deseq.lfc.pdc > 0
write.table(results,"foldchange_results.txt")
table(results$name)

CTCF_and_G4 noPro   CTCF_and_G4 Pro CTCF_not_G4 noPro   CTCF_not_G4 Pro 
              988              1300             43309              6016 
results <- read.table("foldchange_results.txt")
mypal <-c("cornflowerblue","orange","red2","darkgreen","#505050")
mypal2 <-c("cornflowerblue","cornflowerblue","orange","orange","red2","red2","darkgreen","darkgreen","#505050","#505050")
ggviolin(results,x ="class",y="mean.mock",fill="class",palette=mypal,add="mean_sd") + coord_cartesian(ylim=c(0,10))

ggviolin(results,x ="pro",y="mean.mock",fill="class",palette=mypal,add="mean_sd") + coord_cartesian(ylim=c(0,10))

mdf <- reshape2::melt(dplyr::select(results,c("class","mock_1","mock_2","PDS_1","PDS_2","PhenDC3_1","PhenDC3_2")))
Using class as id variables
ggboxplot(mdf,x ="variable",y="value",fill="class",palette=mypal ) + coord_cartesian(ylim=c(0,10))

mdf <- reshape2::melt(dplyr::select(results,c("class","mock_1","mock_2","PDS_1","PDS_2","PhenDC3_1","PhenDC3_2")))
Using class as id variables
ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal,add="mean_sd") + coord_cartesian(ylim=c(0,10))

mdf <- reshape2::melt(dplyr::select(results,c("class","raw.lfc.pds","raw.lfc.pdc")))
Using class as id variables
ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal, add="mean_sd") + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-3,3))
Warning: Removed 49 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 49 rows containing non-finite outside the scale range (`stat_summary()`).

compare_means(raw.lfc.pds ~ class,data = results)
compare_means(raw.lfc.pdc ~ class,data = results,)
mdf <- reshape2::melt(dplyr::select(results,c("class","raw.lfc.pds_1","raw.lfc.pds_2","raw.lfc.pdc_1","raw.lfc.pdc_2")))
Using class as id variables
ggviolin(mdf,x ="variable",y="value",fill="class",palette=mypal, add="mean_sd") + geom_hline(yintercept=0,linetype = "dotted") + coord_cartesian(ylim=c(-4,4))
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 469 rows containing non-finite outside the scale range (`stat_summary()`).

mdf <- reshape2::melt(dplyr::select(results,c("class","raw.lfc.pds","raw.lfc.pdc")))
Using class as id variables
ggboxplot(mdf,x ="variable",y="value",fill="class",palette=mypal) + coord_cartesian(ylim=c(-3,3))
Warning: Removed 49 rows containing non-finite outside the scale range (`stat_boxplot()`).

ggdensity(results,x="raw.lfc.pds",color="class", fill="class",palette=mypal) + geom_vline(xintercept = 0, linetype ="dotted")
Warning: Removed 26 rows containing non-finite outside the scale range (`stat_density()`).

ggdensity(results,x="raw.lfc.pdc",color="class", fill="class",palette=mypal) + geom_vline(xintercept = 0, linetype ="dotted")
Warning: Removed 23 rows containing non-finite outside the scale range (`stat_density()`).

ggscatterhist(results,x ="log2.mock",y="log2.pds",size = 0.2, alpha=0.1,color="deseq.sig.pds",margin.params = list(fill="class",color="black",size=0.2))
Warning: Removed 15 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 12 rows containing non-finite outside the scale range (`stat_density()`).

ggscatterhist(results,x ="log2.mock",y="log2.pdc",size = 0.2, alpha=0.1,color="deseq.sig.pdc",margin.params = list(fill="class",color="black",size=0.2))
Warning: Removed 15 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 8 rows containing non-finite outside the scale range (`stat_density()`).

table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$pro)
       
        noPro   Pro
  FALSE 42094  6938
  TRUE   2200   378
table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2220       46812
  TRUE           68        2510
mdf<-reshape2::melt(table(results$deseq.sig.pds & (results$deseq.lfc.pds > 0),results$class))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

vl <- list(sig=grep("TRUE",results$deseq.sigup.pds),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

table(results$deseq.sig.pdc & (results$deseq.lfc.pdc > 0),results$class)
       
        CTCF_and_G4 CTCF_not_G4
  FALSE        2251       48545
  TRUE           37         780
mdf<-reshape2::melt(table(results$deseq.sig.pdc & (results$deseq.lfc.pdc > 0),results$class))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

results$uid <- seq(1:nrow(results))
vl <- list(sig=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

table(results$deseq.sigup.pds,results$deseq.sigup.pdc)
       
        FALSE  TRUE
  FALSE 48576   456
  TRUE   2217   361
mdf<-reshape2::melt(table(results$deseq.sigup.pds,results$deseq.sigup.pdc))
ggplot(mdf,aes(Var1, Var2, fill= value)) + 
  geom_tile(show.legend = F) + geom_text(aes(label=value)) +
  scale_fill_gradient(low="white", high="orange") + theme_minimal()

vl <- list(sig_PDS=grep("TRUE",results$deseq.sigup.pds),sig_PDC=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class),CTCFonly=grep("not",results$class))
plot(euler(vl),quantities=T)

results$uid <- seq(1:nrow(results))
vl <- list(sig_PDS=grep("TRUE",results$deseq.sigup.pds),sig_PDC=grep("TRUE",results$deseq.sigup.pdc),CTCF_G4=grep("and",results$class))
plot(euler(vl),quantities=T)

results$sig.by.class.pds <- paste0(results$deseq.sigup.pds,"_",results$class)
results$psize <- 0.01
results$psize[results$deseq.sigup.pds] <- 0.5

ggscatter(results[!grepl("NA",results$sig.by.class.pds),],x ="log2.mock",y="log2.pds",size = 0.2, alpha="psize",color = "sig.by.class.pds",palette=c("#505050","#505050","red2","blue"))

ggscatter(results[!grepl("NA",results$sig.by.class.pds),],x ="log2.mock",y="deseq.lfc.pds",size = 0.2, alpha="psize",color = "sig.by.class.pds",palette=c("#505050","#505050","red2","blue"))

ggscatterhist(results[!grepl("NA",results$sig.by.class.pds),],x ="log2.mock",y="log2.pds",size = 0.4, alpha="psize",color = "sig.by.class.pds",margin.params = list(fill="sig.by.class.pds",color="black",size=0.2),palette=c("#505050","#505050","red2","blue"))
Warning: Removed 13 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 10 rows containing non-finite outside the scale range (`stat_density()`).

ggscatter(results,x ="raw.lfc.pds",y="log2.G4",size = 0.2, alpha=0.1,color="class")
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).

ggscatter(results[results$pro=="Pro",],x ="log2.mock",y="G4_NT",size = 0.2, alpha=0.1,color="class",mean.point = T, mean.point.size = 4) + coord_cartesian(ylim=c(0,100))

ggscatter(results,x ="log2.mock",y="G4_NT",size = 0.2, alpha=0.1,color="name",mean.point = T, mean.point.size = 4, palette = mypal) + coord_cartesian(ylim=c(0,50))
Warning: Removed 15 rows containing non-finite outside the scale range (`stat_mean()`).

results$G4.quantile <- cut_number(results$G4_NT, n = 5,labels=F)
ggstripchart(results,x="G4.quantile", y="deseq.lfc.pds",color="red2",add=c("violin","mean_sd"),add.params=list(color="black",fill="cornflowerblue"),size=0.2, alpha=results$deseq.sig.pds/4, palette=mypal) + coord_cartesian(ylim=c(-3,3)) + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).
Warning: Removed 3 rows containing missing values or values outside the scale range
(`geom_point()`).

table(results$G4.quantile,results$deseq.sig.pds)
   
    FALSE TRUE
  1  9565  757
  2  9759  561
  3  9794  529
  4  9916  406
  5  9988  335
ggviolin(results,x="G4.quantile", y="deseq.lfc.pds",fill="cornflowerblue",add="mean_sd") + coord_cartesian(ylim=c(-2,2)) + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_summary()`).

ggviolin(results,x="G4.quantile", y="log2.G4",fill="cornflowerblue",add="mean_sd") + geom_hline(yintercept = 0, linetype="dotted")
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_ydensity()`).
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_summary()`).

ggscatterhist(results,x ="raw.lfc.pds",y="log2.G4",size = 0.2, alpha=0.1,color="deseq.sigup.pds",margin.params = list(fill="deseq.sigup.pds",color="black",size=0.2))
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).
Warning: Removed 26 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_point()`).
Warning: Removed 9483 rows containing non-finite outside the scale range (`stat_density()`).
Warning: Groups with fewer than two data points have been dropped.
Warning in max(ids, na.rm = TRUE) :
  no non-missing arguments to max; returning -Inf

peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile("../data/CutNTag_ChIP-Seq/bw/GSM6634325_E14_Mock_G4.bw",peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2284 generated ( 0.0527909395585346 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 324 generated ( 0.053919121318023 per locus)

peak_cats <- bedscout::import_named_bed_into_list(peaks_bed)
plot_bw_profile(G4_bigwigs,peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)

plot_bw_profile(mocks_bigwigs[1],peak_cats,labels=c(peak_cats[[1]][1,]$name,peak_cats[[2]][1,]$name,peak_cats[[3]][1,]$name,peak_cats[[4]][1,]$name),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 2291 generated ( 0.0529527331561308 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 306 generated ( 0.0509236145781328 per locus)

p1 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[1]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
p2 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[2]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
p3 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[3]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
p4 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[4]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,5,6)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
ggarrange(p1,p2,p3,p4,ncol = 4,nrow = 1)

p1 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[1]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
p2 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[2]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
p3 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[3]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 805 generated ( 0.0186062637235641 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 810 generated ( 0.0187218305789899 per locus)
p4 <- plot_bw_profile(c(mocks_bigwigs,pds_bigwigs),peak_cats[[4]],labels=c("mock1","mock2","trt1","rtr2"),mode="center",show_error = T,verbose=F, remove_top=0.001, colors=mypal2[c(9,10,3,4)],upstream = 1500, downstream=1500)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
Warning in .summarize_matrix(fg, label) :
  Profile plot: 131 generated ( 0.0218006323847562 per locus)
ggarrange(p1,p2,p3,p4,ncol = 4,nrow = 1)

cen we learn something from the genes with top-most increase in CTCF?

sigup.pds <- results[results$deseq.sigup.pds,]
sigup.pdc <- results[results$deseq.sigup.pdc,]

#export.bed(sigup.pds,"peaks_sigup_pds.bed")
#export.bed(sigup.pds,"peaks_sigup_pds.bed")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJkYXRhLnRhYmxlIikKbGlicmFyeSgicnRyYWNrbGF5ZXIiKQpsaWJyYXJ5KCJnZ3Jhc3RyIikKbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgiZ2dwdWJyIikKbGlicmFyeSgid2lnZ2xlc2NvdXQiKQpsaWJyYXJ5KCJldWxlcnIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKCiMgZXhwb3J0IApyZXN1bHRfZm9sZGVyID0gIi4uL3Jlc3VsdHMvd2lnZ2xlc2NvdXQvIgoKYndzIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy8iLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkKCmBgYAoKYGBge3J9CiMgZGlmZiBzaWduYWwgZnVuY3Rpb24KYndfZ3Jhbmdlc19kaWZmX2FuYWx5c2lzIDwtIGZ1bmN0aW9uKGdyYW5nZXNfYzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFuZ2VzX2MyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfYzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlX3NpemVfZmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfZ3JhbmdlcyA9IEZBTFNFKSB7CiAgIyBCaW5kIGZpcnN0LCBnZXQgbnVtYmVycyBhZnRlcgogIG5hbWVzX3ZhbHVlcyA8LSBOVUxMCiAgZmllbGRzIDwtIG5hbWVzKG1jb2xzKGdyYW5nZXNfYzEpKQogIAogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIG5hbWVzX3ZhbHVlcyA8LSBtY29scyhncmFuZ2VzX2MxKVtbIm5hbWUiXV0KICAgIGdyYW5nZXNfYzEgPC0gZ3Jhbmdlc19jMVssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CiAgCiAgZmllbGRzIDwtIG5hbWVzKG1jb2xzKGdyYW5nZXNfYzIpKQogIGlmICgibmFtZSIgJWluJSBmaWVsZHMpIHsKICAgIGdyYW5nZXNfYzIgPC0gZ3Jhbmdlc19jMlssIGZpZWxkc1tmaWVsZHMgIT0gIm5hbWUiXV0KICB9CiAgCiAgY3RzX2RmIDwtIGNiaW5kKGRhdGEuZnJhbWUoZ3Jhbmdlc19jMSksIG1jb2xzKGdyYW5nZXNfYzIpKQogIAogIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICByb3duYW1lcyhjdHNfZGYpIDwtIG5hbWVzX3ZhbHVlcwogIH0KICAKICAjIE5lZWRzIHRvIGRyb3Agbm9uLWNvbXBsZXRlIGNhc2VzIGFuZCBtYXRjaCByb3dzCiAgY29tcGxldGUgPC0gY29tcGxldGUuY2FzZXMoY3RzX2RmKQogIGN0c19kZiA8LSBjdHNfZGZbY29tcGxldGUsIF0KICAKICB2YWx1ZXNfZGYgPC0gY3RzX2RmWywgNjpuY29sKGN0c19kZildICU+JSBkcGx5cjo6c2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKQogIGN0cyA8LSBnZXRfbnJlYWRzX2NvbHVtbnModmFsdWVzX2RmKQogIAogIGNvbmRpdGlvbl9sYWJlbHMgPC0gYyhyZXAobGFiZWxfYzEsIGxlbmd0aChtY29scyhncmFuZ2VzX2MxKSkpLCByZXAobGFiZWxfYzIsIGxlbmd0aChtY29scyhncmFuZ2VzX2MyKSkpKQogIAogIAogIGNvbGRhdGEgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyhjdHMpLCBjb25kaXRpb24gPSBhcy5mYWN0b3IoY29uZGl0aW9uX2xhYmVscykpCiAgcHJpbnQoY29sZGF0YSkKICAKICBkZHMgPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KAogICAgY291bnREYXRhID0gY3RzLAogICAgY29sRGF0YSA9IGNvbGRhdGEsCiAgICBkZXNpZ24gPSB+IGNvbmRpdGlvbiwKICAgIHJvd1JhbmdlcyA9IGdyYW5nZXNfYzFbY29tcGxldGUsIF0KICApCiAgCiAgCiAgaWYgKGVzdGltYXRlX3NpemVfZmFjdG9ycyA9PSBUUlVFKSB7CiAgICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKICB9CiAgZWxzZSB7CiAgICAjIFNpbmNlIGZpbGVzIGFyZSBzY2FsZWQsIHdlIGRvIG5vdCB3YW50IHRvIGVzdGltYXRlIHNpemUgZmFjdG9ycwogICAgc2l6ZUZhY3RvcnMoZGRzKSA8LSBjKHJlcCgxLCBuY29sKGN0cykpKQogIH0KICAKICBkZHMgPC0gREVTZXEyOjplc3RpbWF0ZURpc3BlcnNpb25zKGRkcykKICBkZHMgPC0gREVTZXEyOjpuYmlub21XYWxkVGVzdChkZHMpCiAgCiAgaWYgKGFzX2dyYW5nZXMpIHsKICAgIHJlc3VsdCA8LSBERVNlcTI6OnJlc3VsdHMoZGRzLCBmb3JtYXQgPSAiR1JhbmdlcyIsIGFscGhhID0gMC4wMSkKICAgIGlmICghaXMubnVsbChuYW1lc192YWx1ZXMpKSB7CiAgICAgIHJlc3VsdCRuYW1lIDwtIG5hbWVzX3ZhbHVlc1tjb21wbGV0ZV0KICAgIH0KICAgIAogIH0KICBlbHNlIHsKICAgICMgcmVzdWx0IDwtIHJlc3VsdHMoZGRzLCBmb3JtYXQ9IkRhdGFGcmFtZSIpCiAgICByZXN1bHQgPC0gZGRzCiAgfQogIAogIHJlc3VsdAp9CgpnZXRfbnJlYWRzX2NvbHVtbnMgPC0gZnVuY3Rpb24oZGYsIGxlbmd0aF9mYWN0b3IgPSAxMDApIHsKICAjIENvbnZlcnQgbWVhbiBjb3ZlcmFnZXMgdG8gcm91bmQgaW50ZWdlciByZWFkIG51bWJlcnMKICBjdHMgPC0gYXMubWF0cml4KGRmKQogIGN0cyA8LSBhcy5tYXRyaXgoY3RzW2NvbXBsZXRlLmNhc2VzKGN0cyksIF0pCiAgY3RzIDwtIHJvdW5kKGN0cyAqIGxlbmd0aF9mYWN0b3IpCiAgY3RzCn0KYGBgCgpgYGB7cn0KY3RjZi5hbmQuRzQucHJvIDwtIGltcG9ydCgiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXNfd2l0aF9wcm9tb3RlcnMuc29ydGVkLUNUQ0ZfRzQuYmVkIikKY3RjZi5ub3QuRzQucHJvIDwtIGltcG9ydCgiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXNfd2l0aF9wcm9tb3RlcnMuc29ydGVkLUNUQ0Zvbmx5LmJlZCIpCmN0Y2YuYW5kLkc0Lm5wciA8LSBpbXBvcnQoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzX3dpdGhvdXRfcHJvbW90ZXJzLnNvcnRlZC1DVENGX0c0LmJlZCIpCmN0Y2Yubm90Lkc0Lm5wciA8LSBpbXBvcnQoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzX3dpdGhvdXRfcHJvbW90ZXJzLnNvcnRlZC1DVENGb25seS5iZWQiKQoKY3RjZi5hbmQuRzQucHJvJGNsYXNzIDwtICJDVENGX2FuZF9HNCIKY3RjZi5ub3QuRzQucHJvJGNsYXNzIDwtICJDVENGX25vdF9HNCIKY3RjZi5hbmQuRzQubnByJGNsYXNzIDwtICJDVENGX2FuZF9HNCIKY3RjZi5ub3QuRzQubnByJGNsYXNzIDwtICJDVENGX25vdF9HNCIKY3RjZi5hbmQuRzQucHJvJHBybyA8LSAiUHJvIgpjdGNmLm5vdC5HNC5wcm8kcHJvIDwtICJQcm8iCmN0Y2YuYW5kLkc0Lm5wciRwcm8gPC0gIm5vUHJvIgpjdGNmLm5vdC5HNC5ucHIkcHJvIDwtICJub1BybyIKCmN0Y2YuYW5kLkc0IDwtIGMoY3RjZi5hbmQuRzQucHJvLGN0Y2YuYW5kLkc0Lm5wcikKY3RjZi5ub3QuRzQgPC0gYyhjdGNmLm5vdC5HNC5wcm8sY3RjZi5ub3QuRzQubnByKQpjdGNmIDwtIGMoY3RjZi5hbmQuRzQsY3RjZi5ub3QuRzQpCmN0Y2YgPC0gc29ydFNlcWxldmVscyhjdGNmKQpjdGNmIDwtIHNvcnQoY3RjZikKbmFtZXMoY3RjZikgPC0gcGFzdGUwKGN0Y2YkY2xhc3MsIiAiLGN0Y2YkcHJvKQpwZWFrc19iZWQgPC0gIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9iZWQvV3VsZnJpZGdlX0NUQ0ZfaW5fNl9jYXRlZ29yaWVzLmJlZCIKZXhwb3J0LmJlZChjdGNmLCAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2JlZC9XdWxmcmlkZ2VfQ1RDRl9pbl82X2NhdGVnb3JpZXMuYmVkIikKYGBgCgpgYGB7cn0KIyBXdWxmcmlkZ2UgQ1RDRiBDaElQLVNlcSBtb2Nrcwptb2Nrc19iaWd3aWdzID0gYygiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4Mzg3X0dTTTcxMTYyNzdfRTE0X01vY2tfQ1RDRl9SZXAxX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IiwKICAgICAgICAgICIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODZfR1NNNzExNjI3OF9FMTRfTW9ja19DVENGX1JlcDJfTXVzX211c2N1bHVzX0NoSVAtU2VxLkNQTW5vcm0uYnciKQoKIyBQRFMKIyBXdWxmcmlkZ2UgQ1RDRiBDaElQLVNlcQpwZHNfYmlnd2lncyA9IGMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4NV9HU003MTE2Mjc5X0UxNF9QRFNfQ1RDRl9SZXAxX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IiwKICAgICAgICAgICAgICAgICIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvU1JSMjM5NTgzODRfR1NNNzExNjI4MF9FMTRfUERTX0NUQ0ZfUmVwMl9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIpCgpwZGNfYmlnd2lncyA9IGMoIi4uL2RhdGEvQ3V0TlRhZ19DaElQLVNlcS9idy9TUlIyMzk1ODM4M19HU003MTE2MjgxX0UxNF9QaGVuREMzX0NUQ0ZfUmVwMV9NdXNfbXVzY3VsdXNfQ2hJUC1TZXEuQ1BNbm9ybS5idyIsCiAgICAgICAgICAgICAgICAiLi4vZGF0YS9DdXROVGFnX0NoSVAtU2VxL2J3L1NSUjIzOTU4MzgyX0dTTTcxMTYyODJfRTE0X1BoZW5EQzNfQ1RDRl9SZXAyX011c19tdXNjdWx1c19DaElQLVNlcS5DUE1ub3JtLmJ3IikKCkc0X2JpZ3dpZ3MgPSBjKCIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvRzRfQ25UX05UX2JhdGNoM19SMS51bmlxdWUuYnciKQoKY292Lm1vY2tzIDwtIGJ3X2xvY2kobW9ja3NfYmlnd2lncyxwZWFrc19iZWQsbGFiZWxzPWMoIm1vY2tfMSIsIm1vY2tfMiIpKQpjb3YucGRzIDwtIGJ3X2xvY2kocGRzX2JpZ3dpZ3MscGVha3NfYmVkLGxhYmVscz1jKCJQRFNfMSIsIlBEU18yIikpCmNvdi5wZGMgPC0gYndfbG9jaShwZGNfYmlnd2lncyxwZWFrc19iZWQsbGFiZWxzPWMoIlBoZW5EQzNfMSIsIlBoZW5EQzNfMiIpKQpjb3YuRzQgPC0gYndfbG9jaShHNF9iaWd3aWdzLHBlYWtzX2JlZCxsYWJlbHM9YygiRzRfTlQiKSkKYGBgCgoKYGBge3J9CnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBhcy5kYXRhLmZyYW1lKGNvdi5tb2NrcyksCiAgYXMuZGF0YS5mcmFtZShjb3YucGRzKVs2OjddLAogIGFzLmRhdGEuZnJhbWUoY292LnBkYylbNjo3XSwKICBhcy5kYXRhLmZyYW1lKGNvdi5HNClbNl0sCiAgcmF3LmxmYy5wZHNfMSA9IGxvZzIoY292LnBkcyRQRFNfMS9jb3YubW9ja3MkbW9ja18xKSwKICByYXcubGZjLnBkc18yID0gbG9nMihjb3YucGRzJFBEU18yL2Nvdi5tb2NrcyRtb2NrXzIpLAogIHJhdy5sZmMucGRjXzEgPSBsb2cyKGNvdi5wZHMkUERTXzEvY292Lm1vY2tzJG1vY2tfMSksCiAgcmF3LmxmYy5wZGNfMiA9IGxvZzIoY292LnBkYyRQaGVuREMzXzIvY292Lm1vY2tzJG1vY2tfMiksCiAgcmF3LmxmYy5wZHMgPSBsb2cyKHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LnBkcylbNjo3XSkvcm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YubW9ja3MpWzY6N10pKSwKICByYXcubGZjLnBkYyA9IGxvZzIocm93TWVhbnMoYXMuZGF0YS5mcmFtZShjb3YucGRjKVs2OjddKS9yb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5tb2NrcylbNjo3XSkpLAogIG1lYW4ubW9jayA9IHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292Lm1vY2tzKVs2OjddKSwKICBtZWFuLnBkcyA9IHJvd01lYW5zKGFzLmRhdGEuZnJhbWUoY292LnBkcylbNjo3XSksCiAgbWVhbi5wZGMgPSByb3dNZWFucyhhcy5kYXRhLmZyYW1lKGNvdi5wZGMpWzY6N10pCiAgKQoKY292Lm1vY2tzJG5hbWUgPC0gTlVMTApjb3YucGRzJG5hbWUgPC0gTlVMTApjb3YucGRjJG5hbWUgPC0gTlVMTAoKZGVfcGRzIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsY292LnBkcywiTW9jayIsIlBEUyIpCmxmY19wZHMgPSBERVNlcTI6OmxmY1NocmluayhkZV9wZHMsIGNvZWYgPSAiY29uZGl0aW9uX1BEU192c19Nb2NrIiwgdHlwZSA9ICJhcGVnbG0iKQoKZGVfcGRjIDwtIGJ3X2dyYW5nZXNfZGlmZl9hbmFseXNpcyhjb3YubW9ja3MsY292LnBkYywiTW9jayIsIlBoZW5EQzMiKQpsZmNfcGRjID0gREVTZXEyOjpsZmNTaHJpbmsoZGVfcGRjLCBjb2VmID0gImNvbmRpdGlvbl9QaGVuREMzX3ZzX01vY2siLCB0eXBlID0gImFwZWdsbSIpCgpyZXN1bHRzJGRlc2VxLmxmYy5wZHMgPC0gcmVzdWx0cyhkZV9wZHMpJGxvZzJGb2xkQ2hhbmdlCnJlc3VsdHMkZGVzZXEubGZjcy5wZHMgPC0gbGZjX3BkcyRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLnBhZGoucGRzIDwtIGxmY19wZHMkcGFkagpyZXN1bHRzJGRlc2VxLm1lYW4ucGRzIDwtIGxvZzIobGZjX3BkcyRiYXNlTWVhbikKcmVzdWx0cyRkZXNlcS5zaWcucGRzIDwtIGxmY19wZHMkcHZhbHVlIDwgMC4wNQoKcmVzdWx0cyRkZXNlcS5sZmMucGRjIDwtIHJlc3VsdHMoZGVfcGRjKSRsb2cyRm9sZENoYW5nZQpyZXN1bHRzJGRlc2VxLmxmY3MucGRjIDwtIGxmY19wZGMkbG9nMkZvbGRDaGFuZ2UKcmVzdWx0cyRkZXNlcS5wYWRqLnBkYyA8LSBsZmNfcGRjJHBhZGoKcmVzdWx0cyRkZXNlcS5tZWFuLnBkYyA8LSBsb2cyKGxmY19wZGMkYmFzZU1lYW4pCnJlc3VsdHMkZGVzZXEuc2lnLnBkYyA8LSBsZmNfcGRjJHB2YWx1ZSA8IDAuMDUKCnJlc3VsdHMkY2xhc3MgPC0gZ3N1YigiIC4rIiwiIixyZXN1bHRzJG5hbWUpCnJlc3VsdHMkcHJvIDwtIGdzdWIoIi4rICIsIiIscmVzdWx0cyRuYW1lKQpyZXN1bHRzJGNsYXNzIDwtIGZhY3RvcihyZXN1bHRzJGNsYXNzLGxldmVscz1jKCJDVENGX2FuZF9HNCIsIkNUQ0Zfbm90X0c0IikpCgpyZXN1bHRzJGxvZzIubW9jayA8LSBsb2cyKHJlc3VsdHMkbWVhbi5tb2NrKQpyZXN1bHRzJGxvZzIucGRzIDwtIGxvZzIocmVzdWx0cyRtZWFuLnBkcykKcmVzdWx0cyRsb2cyLnBkYyA8LSBsb2cyKHJlc3VsdHMkbWVhbi5wZGMpCnJlc3VsdHMkbG9nMi5HNCA8LSBsb2cyKHJlc3VsdHMkRzRfTlQpCgpyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyA8LSByZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiByZXN1bHRzJGRlc2VxLmxmYy5wZHMgPiAwCnJlc3VsdHMkZGVzZXEuc2lndXAucGRjIDwtIHJlc3VsdHMkZGVzZXEuc2lnLnBkYyAmIHJlc3VsdHMkZGVzZXEubGZjLnBkYyA+IDAKYGBgCgpgYGB7cn0Kd3JpdGUudGFibGUocmVzdWx0cywiZm9sZGNoYW5nZV9yZXN1bHRzLnR4dCIpCnRhYmxlKHJlc3VsdHMkbmFtZSkKYGBgCgpgYGB7cn0KcmVzdWx0cyA8LSByZWFkLnRhYmxlKCJmb2xkY2hhbmdlX3Jlc3VsdHMudHh0IikKYGBgCgpgYGB7cn0KbXlwYWwgPC1jKCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsInJlZDIiLCJkYXJrZ3JlZW4iLCIjNTA1MDUwIikKbXlwYWwyIDwtYygiY29ybmZsb3dlcmJsdWUiLCJjb3JuZmxvd2VyYmx1ZSIsIm9yYW5nZSIsIm9yYW5nZSIsInJlZDIiLCJyZWQyIiwiZGFya2dyZWVuIiwiZGFya2dyZWVuIiwiIzUwNTA1MCIsIiM1MDUwNTAiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKHJlc3VsdHMseCA9ImNsYXNzIix5PSJtZWFuLm1vY2siLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsLGFkZD0ibWVhbl9zZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDEwKSkKYGBgCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdndmlvbGluKHJlc3VsdHMseCA9InBybyIseT0ibWVhbi5tb2NrIixmaWxsPSJjbGFzcyIscGFsZXR0ZT1teXBhbCxhZGQ9Im1lYW5fc2QiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRwbHlyOjpzZWxlY3QocmVzdWx0cyxjKCJjbGFzcyIsIm1vY2tfMSIsIm1vY2tfMiIsIlBEU18xIiwiUERTXzIiLCJQaGVuREMzXzEiLCJQaGVuREMzXzIiKSkpCmdnYm94cGxvdChtZGYseCA9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwgKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRwbHlyOjpzZWxlY3QocmVzdWx0cyxjKCJjbGFzcyIsIm1vY2tfMSIsIm1vY2tfMiIsIlBEU18xIiwiUERTXzIiLCJQaGVuREMzXzEiLCJQaGVuREMzXzIiKSkpCmdndmlvbGluKG1kZix4ID0idmFyaWFibGUiLHk9InZhbHVlIixmaWxsPSJjbGFzcyIscGFsZXR0ZT1teXBhbCxhZGQ9Im1lYW5fc2QiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxMCkpCmBgYApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQptZGYgPC0gcmVzaGFwZTI6Om1lbHQoZHBseXI6OnNlbGVjdChyZXN1bHRzLGMoImNsYXNzIiwicmF3LmxmYy5wZHMiLCJyYXcubGZjLnBkYyIpKSkKZ2d2aW9saW4obWRmLHggPSJ2YXJpYWJsZSIseT0idmFsdWUiLGZpbGw9ImNsYXNzIixwYWxldHRlPW15cGFsLCBhZGQ9Im1lYW5fc2QiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLGxpbmV0eXBlID0gImRvdHRlZCIpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMywzKSkKYGBgCgpgYGB7cn0KY29tcGFyZV9tZWFucyhyYXcubGZjLnBkcyB+IGNsYXNzLGRhdGEgPSByZXN1bHRzKQpgYGAKCmBgYHtyfQpjb21wYXJlX21lYW5zKHJhdy5sZmMucGRjIH4gY2xhc3MsZGF0YSA9IHJlc3VsdHMsKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTN9Cm1kZiA8LSByZXNoYXBlMjo6bWVsdChkcGx5cjo6c2VsZWN0KHJlc3VsdHMsYygiY2xhc3MiLCJyYXcubGZjLnBkc18xIiwicmF3LmxmYy5wZHNfMiIsInJhdy5sZmMucGRjXzEiLCJyYXcubGZjLnBkY18yIikpKQpnZ3Zpb2xpbihtZGYseCA9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwsIGFkZD0ibWVhbl9zZCIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsbGluZXR5cGUgPSAiZG90dGVkIikgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC00LDQpKQpgYGAKYGBge3IgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9M30KbWRmIDwtIHJlc2hhcGUyOjptZWx0KGRwbHlyOjpzZWxlY3QocmVzdWx0cyxjKCJjbGFzcyIsInJhdy5sZmMucGRzIiwicmF3LmxmYy5wZGMiKSkpCmdnYm94cGxvdChtZGYseCA9InZhcmlhYmxlIix5PSJ2YWx1ZSIsZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygtMywzKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpnZ2RlbnNpdHkocmVzdWx0cyx4PSJyYXcubGZjLnBkcyIsY29sb3I9ImNsYXNzIiwgZmlsbD0iY2xhc3MiLHBhbGV0dGU9bXlwYWwpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSJkb3R0ZWQiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmdnZGVuc2l0eShyZXN1bHRzLHg9InJhdy5sZmMucGRjIixjb2xvcj0iY2xhc3MiLCBmaWxsPSJjbGFzcyIscGFsZXR0ZT1teXBhbCkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ImRvdHRlZCIpCmBgYAoKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9Cmdnc2NhdHRlcmhpc3QocmVzdWx0cyx4ID0ibG9nMi5tb2NrIix5PSJsb2cyLnBkcyIsc2l6ZSA9IDAuMiwgYWxwaGE9MC4xLGNvbG9yPSJkZXNlcS5zaWcucGRzIixtYXJnaW4ucGFyYW1zID0gbGlzdChmaWxsPSJjbGFzcyIsY29sb3I9ImJsYWNrIixzaXplPTAuMikpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpnZ3NjYXR0ZXJoaXN0KHJlc3VsdHMseCA9ImxvZzIubW9jayIseT0ibG9nMi5wZGMiLHNpemUgPSAwLjIsIGFscGhhPTAuMSxjb2xvcj0iZGVzZXEuc2lnLnBkYyIsbWFyZ2luLnBhcmFtcyA9IGxpc3QoZmlsbD0iY2xhc3MiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpKQpgYGAKCmBgYHtyfQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRwcm8pCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRjbGFzcykKbWRmPC1yZXNoYXBlMjo6bWVsdCh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZHMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRzID4gMCkscmVzdWx0cyRjbGFzcykpCmdncGxvdChtZGYsYWVzKFZhcjEsIFZhcjIsIGZpbGw9IHZhbHVlKSkgKyAKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWw9dmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD0ib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgpgYGB7cn0KdmwgPC0gbGlzdChzaWc9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMpLENUQ0ZfRzQ9Z3JlcCgiYW5kIixyZXN1bHRzJGNsYXNzKSxDVENGb25seT1ncmVwKCJub3QiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9Mi41fQp0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRjID4gMCkscmVzdWx0cyRjbGFzcykKbWRmPC1yZXNoYXBlMjo6bWVsdCh0YWJsZShyZXN1bHRzJGRlc2VxLnNpZy5wZGMgJiAocmVzdWx0cyRkZXNlcS5sZmMucGRjID4gMCkscmVzdWx0cyRjbGFzcykpCmdncGxvdChtZGYsYWVzKFZhcjEsIFZhcjIsIGZpbGw9IHZhbHVlKSkgKyAKICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGKSArIGdlb21fdGV4dChhZXMobGFiZWw9dmFsdWUpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD0ib3JhbmdlIikgKyB0aGVtZV9taW5pbWFsKCkKYGBgCgoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3Qoc2lnPWdyZXAoIlRSVUUiLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKSxDVENGX0c0PWdyZXAoImFuZCIscmVzdWx0cyRjbGFzcyksQ1RDRm9ubHk9Z3JlcCgibm90IixyZXN1bHRzJGNsYXNzKSkKcGxvdChldWxlcih2bCkscXVhbnRpdGllcz1UKQpgYGAKIApgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0yLjV9CnRhYmxlKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKQptZGY8LXJlc2hhcGUyOjptZWx0KHRhYmxlKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLHJlc3VsdHMkZGVzZXEuc2lndXAucGRjKSkKZ2dwbG90KG1kZixhZXMoVmFyMSwgVmFyMiwgZmlsbD0gdmFsdWUpKSArIAogIGdlb21fdGlsZShzaG93LmxlZ2VuZCA9IEYpICsgZ2VvbV90ZXh0KGFlcyhsYWJlbD12YWx1ZSkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLCBoaWdoPSJvcmFuZ2UiKSArIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQp2bCA8LSBsaXN0KHNpZ19QRFM9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZHMpLHNpZ19QREM9Z3JlcCgiVFJVRSIscmVzdWx0cyRkZXNlcS5zaWd1cC5wZGMpLENUQ0ZfRzQ9Z3JlcCgiYW5kIixyZXN1bHRzJGNsYXNzKSxDVENGb25seT1ncmVwKCJub3QiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYAoKYGBge3J9CnJlc3VsdHMkdWlkIDwtIHNlcSgxOm5yb3cocmVzdWx0cykpCnZsIDwtIGxpc3Qoc2lnX1BEUz1ncmVwKCJUUlVFIixyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyksc2lnX1BEQz1ncmVwKCJUUlVFIixyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkYyksQ1RDRl9HND1ncmVwKCJhbmQiLHJlc3VsdHMkY2xhc3MpKQpwbG90KGV1bGVyKHZsKSxxdWFudGl0aWVzPVQpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpyZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMgPC0gcGFzdGUwKHJlc3VsdHMkZGVzZXEuc2lndXAucGRzLCJfIixyZXN1bHRzJGNsYXNzKQpyZXN1bHRzJHBzaXplIDwtIDAuMDEKcmVzdWx0cyRwc2l6ZVtyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkc10gPC0gMC41CgpnZ3NjYXR0ZXIocmVzdWx0c1shZ3JlcGwoIk5BIixyZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMpLF0seCA9ImxvZzIubW9jayIseT0ibG9nMi5wZHMiLHNpemUgPSAwLjIsIGFscGhhPSJwc2l6ZSIsY29sb3IgPSAic2lnLmJ5LmNsYXNzLnBkcyIscGFsZXR0ZT1jKCIjNTA1MDUwIiwiIzUwNTA1MCIsInJlZDIiLCJibHVlIikpCmBgYApgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpnZ3NjYXR0ZXIocmVzdWx0c1shZ3JlcGwoIk5BIixyZXN1bHRzJHNpZy5ieS5jbGFzcy5wZHMpLF0seCA9ImxvZzIubW9jayIseT0iZGVzZXEubGZjLnBkcyIsc2l6ZSA9IDAuMiwgYWxwaGE9InBzaXplIixjb2xvciA9ICJzaWcuYnkuY2xhc3MucGRzIixwYWxldHRlPWMoIiM1MDUwNTAiLCIjNTA1MDUwIiwicmVkMiIsImJsdWUiKSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQpnZ3NjYXR0ZXJoaXN0KHJlc3VsdHNbIWdyZXBsKCJOQSIscmVzdWx0cyRzaWcuYnkuY2xhc3MucGRzKSxdLHggPSJsb2cyLm1vY2siLHk9ImxvZzIucGRzIixzaXplID0gMC40LCBhbHBoYT0icHNpemUiLGNvbG9yID0gInNpZy5ieS5jbGFzcy5wZHMiLG1hcmdpbi5wYXJhbXMgPSBsaXN0KGZpbGw9InNpZy5ieS5jbGFzcy5wZHMiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpLHBhbGV0dGU9YygiIzUwNTA1MCIsIiM1MDUwNTAiLCJyZWQyIiwiYmx1ZSIpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9Cmdnc2NhdHRlcihyZXN1bHRzLHggPSJyYXcubGZjLnBkcyIseT0ibG9nMi5HNCIsc2l6ZSA9IDAuMiwgYWxwaGE9MC4xLGNvbG9yPSJjbGFzcyIpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpnZ3NjYXR0ZXIocmVzdWx0c1tyZXN1bHRzJHBybz09IlBybyIsXSx4ID0ibG9nMi5tb2NrIix5PSJHNF9OVCIsc2l6ZSA9IDAuMiwgYWxwaGE9MC4xLGNvbG9yPSJjbGFzcyIsbWVhbi5wb2ludCA9IFQsIG1lYW4ucG9pbnQuc2l6ZSA9IDQpICsgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDEwMCkpCmBgYApgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpnZ3NjYXR0ZXIocmVzdWx0cyx4ID0ibG9nMi5tb2NrIix5PSJHNF9OVCIsc2l6ZSA9IDAuMiwgYWxwaGE9MC4xLGNvbG9yPSJuYW1lIixtZWFuLnBvaW50ID0gVCwgbWVhbi5wb2ludC5zaXplID0gNCwgcGFsZXR0ZSA9IG15cGFsKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw1MCkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcmVzdWx0cyRHNC5xdWFudGlsZSA8LSBjdXRfbnVtYmVyKHJlc3VsdHMkRzRfTlQsIG4gPSA1LGxhYmVscz1GKQpnZ3N0cmlwY2hhcnQocmVzdWx0cyx4PSJHNC5xdWFudGlsZSIsIHk9ImRlc2VxLmxmYy5wZHMiLGNvbG9yPSJyZWQyIixhZGQ9YygidmlvbGluIiwibWVhbl9zZCIpLGFkZC5wYXJhbXM9bGlzdChjb2xvcj0iYmxhY2siLGZpbGw9ImNvcm5mbG93ZXJibHVlIiksc2l6ZT0wLjIsIGFscGhhPXJlc3VsdHMkZGVzZXEuc2lnLnBkcy80LCBwYWxldHRlPW15cGFsKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTMsMykpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRvdHRlZCIpCmBgYApgYGB7cn0KdGFibGUocmVzdWx0cyRHNC5xdWFudGlsZSxyZXN1bHRzJGRlc2VxLnNpZy5wZHMpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4ocmVzdWx0cyx4PSJHNC5xdWFudGlsZSIsIHk9ImRlc2VxLmxmYy5wZHMiLGZpbGw9ImNvcm5mbG93ZXJibHVlIixhZGQ9Im1lYW5fc2QiKSArIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTIsMikpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9ImRvdHRlZCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KZ2d2aW9saW4ocmVzdWx0cyx4PSJHNC5xdWFudGlsZSIsIHk9ImxvZzIuRzQiLGZpbGw9ImNvcm5mbG93ZXJibHVlIixhZGQ9Im1lYW5fc2QiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlPSJkb3R0ZWQiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9Cmdnc2NhdHRlcmhpc3QocmVzdWx0cyx4ID0icmF3LmxmYy5wZHMiLHk9ImxvZzIuRzQiLHNpemUgPSAwLjIsIGFscGhhPTAuMSxjb2xvcj0iZGVzZXEuc2lndXAucGRzIixtYXJnaW4ucGFyYW1zID0gbGlzdChmaWxsPSJkZXNlcS5zaWd1cC5wZHMiLGNvbG9yPSJibGFjayIsc2l6ZT0wLjIpKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwZWFrX2NhdHMgPC0gYmVkc2NvdXQ6OmltcG9ydF9uYW1lZF9iZWRfaW50b19saXN0KHBlYWtzX2JlZCkKcGxvdF9id19wcm9maWxlKCIuLi9kYXRhL0N1dE5UYWdfQ2hJUC1TZXEvYncvR1NNNjYzNDMyNV9FMTRfTW9ja19HNC5idyIscGVha19jYXRzLGxhYmVscz1jKHBlYWtfY2F0c1tbMV1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbMl1dWzEsXSRuYW1lLHBlYWtfY2F0c1tbM11dWzEsXSRuYW1lLHBlYWtfY2F0c1tbNF1dWzEsXSRuYW1lKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsKQpgYGAKYGBge3IgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGVha19jYXRzIDwtIGJlZHNjb3V0OjppbXBvcnRfbmFtZWRfYmVkX2ludG9fbGlzdChwZWFrc19iZWQpCnBsb3RfYndfcHJvZmlsZShHNF9iaWd3aWdzLHBlYWtfY2F0cyxsYWJlbHM9YyhwZWFrX2NhdHNbWzFdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzJdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzNdXVsxLF0kbmFtZSxwZWFrX2NhdHNbWzRdXVsxLF0kbmFtZSksbW9kZT0iY2VudGVyIixzaG93X2Vycm9yID0gVCx2ZXJib3NlPUYsIHJlbW92ZV90b3A9MC4wMDEsIGNvbG9ycz1teXBhbCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpwbG90X2J3X3Byb2ZpbGUobW9ja3NfYmlnd2lnc1sxXSxwZWFrX2NhdHMsbGFiZWxzPWMocGVha19jYXRzW1sxXV1bMSxdJG5hbWUscGVha19jYXRzW1syXV1bMSxdJG5hbWUscGVha19jYXRzW1szXV1bMSxdJG5hbWUscGVha19jYXRzW1s0XV1bMSxdJG5hbWUpLG1vZGU9ImNlbnRlciIsc2hvd19lcnJvciA9IFQsdmVyYm9zZT1GLCByZW1vdmVfdG9wPTAuMDAxLCBjb2xvcnM9bXlwYWwpCmBgYAoKCgoKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTN9CnAxIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbMV1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsNSw2KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnAyIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbMl1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsNSw2KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnAzIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbM11dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsNSw2KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnA0IDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbNF1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsNSw2KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCgpnZ2FycmFuZ2UocDEscDIscDMscDQsbmNvbCA9IDQsbnJvdyA9IDEpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTN9CnAxIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbMV1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsMyw0KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnAyIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbMl1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsMyw0KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnAzIDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbM11dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsMyw0KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCnA0IDwtIHBsb3RfYndfcHJvZmlsZShjKG1vY2tzX2JpZ3dpZ3MscGRzX2JpZ3dpZ3MpLHBlYWtfY2F0c1tbNF1dLGxhYmVscz1jKCJtb2NrMSIsIm1vY2syIiwidHJ0MSIsInJ0cjIiKSxtb2RlPSJjZW50ZXIiLHNob3dfZXJyb3IgPSBULHZlcmJvc2U9RiwgcmVtb3ZlX3RvcD0wLjAwMSwgY29sb3JzPW15cGFsMltjKDksMTAsMyw0KV0sdXBzdHJlYW0gPSAxNTAwLCBkb3duc3RyZWFtPTE1MDApCgpnZ2FycmFuZ2UocDEscDIscDMscDQsbmNvbCA9IDQsbnJvdyA9IDEpCmBgYAojIyMgY2VuIHdlIGxlYXJuIHNvbWV0aGluZyBmcm9tIHRoZSBnZW5lcyB3aXRoIHRvcC1tb3N0IGluY3JlYXNlIGluIENUQ0Y/CmBgYHtyfQpzaWd1cC5wZHMgPC0gcmVzdWx0c1tyZXN1bHRzJGRlc2VxLnNpZ3VwLnBkcyxdCnNpZ3VwLnBkYyA8LSByZXN1bHRzW3Jlc3VsdHMkZGVzZXEuc2lndXAucGRjLF0KCiNleHBvcnQuYmVkKHNpZ3VwLnBkcywicGVha3Nfc2lndXBfcGRzLmJlZCIpCiNleHBvcnQuYmVkKHNpZ3VwLnBkcywicGVha3Nfc2lndXBfcGRzLmJlZCIpCmBgYA==